package com.tools.scanner.utils

import android.os.Build
import com.airbnb.lottie.animation.keyframe.PathKeyframe
import com.google.android.gms.ads.AdValue
import com.mixpanel.android.mpmetrics.MixpanelAPI
import com.tools.scanner.BuildConfig
import com.tools.scanner.QrApp
import com.tools.scanner.bean.SharePlatformInfo
import org.json.JSONException
import org.json.JSONObject
import java.util.Random

object DataReportUtil {

    private const val AD_ID: String = "adId"
    private const val AD_LOCATION: String = "adLocation"
    private const val ERROR_CODE: String = "errorCode"
    private const val ERROR_MESSAGE: String = "errorMsg"
    private const val USE_TIME: String = "useTime"
    private const val AD_VALUE: String = "ad_value"
    private const val AD_CURRENCY: String = "ad_currency"
    private const val AD_PRECISION: String = "ad_precision"
    private const val AD_SEQ: String = "ad_seq"
    private const val AD_SOURCE: String = "ad_source"
    private const val PACKAGE_NAME = "pkg"
    private const val SHARE_LABEL = "label"
    private const val SCENE = "scene"

    private lateinit var mp: MixpanelAPI

    private val dataBufferList = mutableListOf<DataBuffer>()

    fun init(referrer: String) {
        val context = QrApp.app

        val language = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            context.resources.configuration.getLocales().get(0).language
        } else {
            context.resources.configuration.locale.language
        }

        val jsonObject = JSONObject()
        jsonObject.put("referrer_url", referrer)
        jsonObject.put("language", language)

        val token = BuildConfig.MIX_TOKEN
        mp = MixpanelAPI.getInstance(context, token, jsonObject, true)

        synchronized(dataBufferList) {
            val size = dataBufferList.size

            for (i in 0 until size) {
                val buffer = dataBufferList.removeAt(0)
                mp.track(buffer.event, buffer.jsonObject)
            }
        }
    }

    fun reportShareOpen() {
        val event = "share_open"
        trackEvent(event, null)
    }

    fun reportShareClick(info: SharePlatformInfo) {
        val event = "share_click"

        val jsonObject = JSONObject()
        try {
            jsonObject.put(PACKAGE_NAME, info.packageName)
            jsonObject.put(SHARE_LABEL, info.label)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportScanCodeFail(content: String) {
        val event = "scan_code_fail"

        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_MESSAGE, content)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportCaptureFail(content: String) {
        val event = "capture_fail"

        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_MESSAGE, content)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportOcrFail(content: String) {
        val event = "ocr_fail"

        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_MESSAGE, content)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportRecognizeFail() {
        val event = "recognize_fail"
        trackEvent(event, null)
    }

    fun reportTranslator() {
        val event = "translator"
        trackEvent(event, null)
    }

    fun reportCreateQrCodeFail(type: Int) {
        val event = "create_qr_code_fail"

        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_CODE, type)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportOpenPdfFail(content: String) {
        val event = "open_pdf_fail"

        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_MESSAGE, content)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportCreatePdfFail() {
        val event = "create_pdf_fail"
        trackEvent(event, null)
    }

    fun reportCreatePdfSuccess() {
        val event = "create_pdf_success"
        trackEvent(event, null)
    }

    fun reportClickPdfShare() {
        val event = "pdf_share"
        trackEvent(event, null)
    }

    fun reportPdfShareFil(content: String) {
        val event = "pdf_share_fail"
        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_MESSAGE, content)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportClickPdfSave() {
        val event = "pdf_save"
        trackEvent(event, null)
    }

    fun reportClickMainTab(index: Int) {
        val event = "click_main_tab"
        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_CODE, index)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportClickHistory() {
        val event = "click_history"
        trackEvent(event, null)
    }

    fun reportClickRateUs() {
        val event = "click_rate_us"
        trackEvent(event, null)
    }

    fun reportClickFeedback() {
        val event = "click_feedback"
        trackEvent(event, null)
    }

    fun reportClickShare() {
        val event = "click_share"
        trackEvent(event, null)
    }

    fun reportRateUsOpen() {
        val event = "rate_us_open"
        trackEvent(event, null)
    }

    fun reportRateUsOpenFail(code: Int, message: String) {
        val event = "rate_us_open_fail"
        val jsonObject = JSONObject()
        try {
            jsonObject.put(ERROR_CODE, code)
            jsonObject.put(ERROR_MESSAGE, message)
            trackEvent(event, jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportAdLoadBegin(adLocation: String, adId: String, seq: String) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_SEQ, seq)
            trackEvent("ad_load_begin", jsonObject)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    fun reportAdLoadEnd(
        adLocation: String,
        adId: String,
        code: Int,
        message: String,
        useTime: Long,
        seq: String,
        source: String
    ) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(ERROR_CODE, code)
            jsonObject.put(ERROR_MESSAGE, message)
            jsonObject.put(USE_TIME, useTime)
            jsonObject.put(USE_TIME, useTime)
            jsonObject.put(AD_SEQ, seq)
            jsonObject.put(AD_SOURCE, source)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_load_end", jsonObject)
    }

    fun reportAdClick(adLocation: String, adId: String, seq: String) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_click", jsonObject)
    }

    fun reportAdClose(adLocation: String, adId: String, seq: String) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_close", jsonObject)
    }

    fun reportAdShowFail(
        adLocation: String,
        adId: String,
        seq: String,
        code: Int,
        message: String
    ) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(ERROR_CODE, code)
            jsonObject.put(ERROR_MESSAGE, message)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_show_fail", jsonObject)
    }

    fun reportAdPrepareShow(adLocation: String, adId: String, seq: String) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_prepare_show", jsonObject)
    }

    fun reportAdShow(adLocation: String, adId: String, seq: String) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_show", jsonObject)
    }

    fun reportAdReward(adLocation: String, adId: String, seq: String) {
        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_reward", jsonObject)
    }

    fun reportAdPaid(adLocation: String, adId: String, seq: String, adValue: AdValue) {
        val value = adValue.valueMicros.toString()
        val currencyCode = adValue.currencyCode
        val precision = adValue.precisionType.toString()

        val jsonObject = JSONObject()
        try {
            jsonObject.put(AD_LOCATION, adLocation)
            jsonObject.put(AD_ID, adId)
            jsonObject.put(AD_VALUE, value)
            jsonObject.put(AD_CURRENCY, currencyCode)
            jsonObject.put(AD_PRECISION, precision)
            jsonObject.put(AD_SEQ, seq)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        trackEvent("ad_paid", jsonObject)
    }

    fun trackEvent(event: String, jsonObject: JSONObject?) {
        val commonParams = getCommonParams()
        jsonObject?.keys()?.forEach {
            commonParams.put(it, jsonObject.getString(it))
        }

        if (!this::mp.isInitialized) {
            addBufferData(event, commonParams)
            return
        }
        mp.track(event, commonParams)
    }

    private fun addBufferData(event: String, jsonObject: JSONObject?) {
        synchronized(dataBufferList) {
            if (this::mp.isInitialized) {
                return
            }
            dataBufferList.add(DataBuffer(event, jsonObject))
        }
    }

    private fun getCommonParams(): JSONObject {
        val jsonObject = JSONObject()
        return jsonObject
    }

    public fun generateUUID(): String {
        val uuid = StringBuilder()
        for (i in 0 until 16) {
            uuid.append(Integer.toHexString(Random().nextInt(16)))
        }
        return uuid.toString()
    }

    data class DataBuffer(val event: String, val jsonObject: JSONObject?)
}